handle case where sibling == iter (gtk_tree_store_insert_after): handle
authorHavoc Pennington <hp@redhat.com>
Wed, 10 Jan 2001 23:44:22 +0000 (23:44 +0000)
committerHavoc Pennington <hp@src.gnome.org>
Wed, 10 Jan 2001 23:44:22 +0000 (23:44 +0000)
2001-01-10  Havoc Pennington  <hp@redhat.com>

* gtk/gtktreestore.c (gtk_tree_store_insert_before): handle case
where sibling == iter
(gtk_tree_store_insert_after): handle sibling == iter
(gtk_tree_store_prepend): remove stamp checks
(gtk_tree_store_insert_before): ditto
(gtk_tree_store_append): ditto
(gtk_tree_store_get_path): ditto
(gtk_tree_store_get_value): ditto
(gtk_tree_store_iter_has_child): ditto
(gtk_tree_store_iter_n_children): ditto
(gtk_tree_store_iter_nth_child): ditto
(gtk_tree_store_insert_after): ditto
(gtk_tree_store_is_ancestor): ditto
(gtk_tree_store_iter_depth): ditto
(gtk_tree_store_insert_before): assert that sibling's parent is
the same as the passed-in parent
(gtk_tree_store_insert_after): assert that sibling's parent is
the same as the passed-in parent

* gtk/gtktreemodel.c (gtk_tree_model_get_first): new convenience
function to get the first iterator in a model

* gtk/gtktreestore.c (gtk_tree_store_get_root_iter): remove,
conventionally the "root" in this sense is just NULL afaict.

* gtk/gtkliststore.c (gtk_list_store_insert_before): handle case
where sibling == iter
(gtk_list_store_insert_after): handle case where sibling == iter

* tests/testtreeview.c (run_automated_tests): fairly lame basic
automated tests for ListStore, TreeStore

        * gtk/gtkliststore.c (gtk_list_store_remove): update tail pointer
(gtk_list_store_insert): update tail pointer, and fix it to work
(gtk_list_store_insert_before): update tail pointer, and fix it to work
(gtk_list_store_append): use tail to be faster
(gtk_list_store_prepend): fix it, update tail pointer
(gtk_list_store_insert_after): fix it, update tail pointer

* gtk/gtkliststore.h (struct _GtkListStore): add tail pointer for
the list

14 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gtk/gtkliststore.c
gtk/gtkliststore.h
gtk/gtktreemodel.c
gtk/gtktreemodel.h
gtk/gtktreestore.c
gtk/gtktreestore.h
tests/testtreeview.c

index 39ee2fb8283c263641fb917dff0fefcfc0c14dda..8e480dd1dc91091f86be723c8731d910faf10e87 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,48 @@
+2001-01-10  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreestore.c (gtk_tree_store_insert_before): handle case
+       where sibling == iter
+       (gtk_tree_store_insert_after): handle sibling == iter
+       (gtk_tree_store_prepend): remove stamp checks
+       (gtk_tree_store_insert_before): ditto
+       (gtk_tree_store_append): ditto
+       (gtk_tree_store_get_path): ditto
+       (gtk_tree_store_get_value): ditto
+       (gtk_tree_store_iter_has_child): ditto
+       (gtk_tree_store_iter_n_children): ditto
+       (gtk_tree_store_iter_nth_child): ditto
+       (gtk_tree_store_insert_after): ditto
+       (gtk_tree_store_is_ancestor): ditto
+       (gtk_tree_store_iter_depth): ditto
+       (gtk_tree_store_insert_before): assert that sibling's parent is
+       the same as the passed-in parent
+       (gtk_tree_store_insert_after): assert that sibling's parent is
+       the same as the passed-in parent
+
+       
+       * gtk/gtktreemodel.c (gtk_tree_model_get_first): new convenience 
+       function to get the first iterator in a model
+       
+       * gtk/gtktreestore.c (gtk_tree_store_get_root_iter): remove,
+       conventionally the "root" in this sense is just NULL afaict.
+
+       * gtk/gtkliststore.c (gtk_list_store_insert_before): handle case
+       where sibling == iter
+       (gtk_list_store_insert_after): handle case where sibling == iter
+
+       * tests/testtreeview.c (run_automated_tests): fairly lame basic
+       automated tests for ListStore, TreeStore
+
+        * gtk/gtkliststore.c (gtk_list_store_remove): update tail pointer
+       (gtk_list_store_insert): update tail pointer, and fix it to work
+       (gtk_list_store_insert_before): update tail pointer, and fix it to work
+       (gtk_list_store_append): use tail to be faster
+       (gtk_list_store_prepend): fix it, update tail pointer
+       (gtk_list_store_insert_after): fix it, update tail pointer
+
+       * gtk/gtkliststore.h (struct _GtkListStore): add tail pointer for 
+       the list
+
 2001-01-09  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtklabel.c (gtk_label_expose): don't draw if label->layout
index 39ee2fb8283c263641fb917dff0fefcfc0c14dda..8e480dd1dc91091f86be723c8731d910faf10e87 100644 (file)
@@ -1,3 +1,48 @@
+2001-01-10  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreestore.c (gtk_tree_store_insert_before): handle case
+       where sibling == iter
+       (gtk_tree_store_insert_after): handle sibling == iter
+       (gtk_tree_store_prepend): remove stamp checks
+       (gtk_tree_store_insert_before): ditto
+       (gtk_tree_store_append): ditto
+       (gtk_tree_store_get_path): ditto
+       (gtk_tree_store_get_value): ditto
+       (gtk_tree_store_iter_has_child): ditto
+       (gtk_tree_store_iter_n_children): ditto
+       (gtk_tree_store_iter_nth_child): ditto
+       (gtk_tree_store_insert_after): ditto
+       (gtk_tree_store_is_ancestor): ditto
+       (gtk_tree_store_iter_depth): ditto
+       (gtk_tree_store_insert_before): assert that sibling's parent is
+       the same as the passed-in parent
+       (gtk_tree_store_insert_after): assert that sibling's parent is
+       the same as the passed-in parent
+
+       
+       * gtk/gtktreemodel.c (gtk_tree_model_get_first): new convenience 
+       function to get the first iterator in a model
+       
+       * gtk/gtktreestore.c (gtk_tree_store_get_root_iter): remove,
+       conventionally the "root" in this sense is just NULL afaict.
+
+       * gtk/gtkliststore.c (gtk_list_store_insert_before): handle case
+       where sibling == iter
+       (gtk_list_store_insert_after): handle case where sibling == iter
+
+       * tests/testtreeview.c (run_automated_tests): fairly lame basic
+       automated tests for ListStore, TreeStore
+
+        * gtk/gtkliststore.c (gtk_list_store_remove): update tail pointer
+       (gtk_list_store_insert): update tail pointer, and fix it to work
+       (gtk_list_store_insert_before): update tail pointer, and fix it to work
+       (gtk_list_store_append): use tail to be faster
+       (gtk_list_store_prepend): fix it, update tail pointer
+       (gtk_list_store_insert_after): fix it, update tail pointer
+
+       * gtk/gtkliststore.h (struct _GtkListStore): add tail pointer for 
+       the list
+
 2001-01-09  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtklabel.c (gtk_label_expose): don't draw if label->layout
index 39ee2fb8283c263641fb917dff0fefcfc0c14dda..8e480dd1dc91091f86be723c8731d910faf10e87 100644 (file)
@@ -1,3 +1,48 @@
+2001-01-10  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreestore.c (gtk_tree_store_insert_before): handle case
+       where sibling == iter
+       (gtk_tree_store_insert_after): handle sibling == iter
+       (gtk_tree_store_prepend): remove stamp checks
+       (gtk_tree_store_insert_before): ditto
+       (gtk_tree_store_append): ditto
+       (gtk_tree_store_get_path): ditto
+       (gtk_tree_store_get_value): ditto
+       (gtk_tree_store_iter_has_child): ditto
+       (gtk_tree_store_iter_n_children): ditto
+       (gtk_tree_store_iter_nth_child): ditto
+       (gtk_tree_store_insert_after): ditto
+       (gtk_tree_store_is_ancestor): ditto
+       (gtk_tree_store_iter_depth): ditto
+       (gtk_tree_store_insert_before): assert that sibling's parent is
+       the same as the passed-in parent
+       (gtk_tree_store_insert_after): assert that sibling's parent is
+       the same as the passed-in parent
+
+       
+       * gtk/gtktreemodel.c (gtk_tree_model_get_first): new convenience 
+       function to get the first iterator in a model
+       
+       * gtk/gtktreestore.c (gtk_tree_store_get_root_iter): remove,
+       conventionally the "root" in this sense is just NULL afaict.
+
+       * gtk/gtkliststore.c (gtk_list_store_insert_before): handle case
+       where sibling == iter
+       (gtk_list_store_insert_after): handle case where sibling == iter
+
+       * tests/testtreeview.c (run_automated_tests): fairly lame basic
+       automated tests for ListStore, TreeStore
+
+        * gtk/gtkliststore.c (gtk_list_store_remove): update tail pointer
+       (gtk_list_store_insert): update tail pointer, and fix it to work
+       (gtk_list_store_insert_before): update tail pointer, and fix it to work
+       (gtk_list_store_append): use tail to be faster
+       (gtk_list_store_prepend): fix it, update tail pointer
+       (gtk_list_store_insert_after): fix it, update tail pointer
+
+       * gtk/gtkliststore.h (struct _GtkListStore): add tail pointer for 
+       the list
+
 2001-01-09  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtklabel.c (gtk_label_expose): don't draw if label->layout
index 39ee2fb8283c263641fb917dff0fefcfc0c14dda..8e480dd1dc91091f86be723c8731d910faf10e87 100644 (file)
@@ -1,3 +1,48 @@
+2001-01-10  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreestore.c (gtk_tree_store_insert_before): handle case
+       where sibling == iter
+       (gtk_tree_store_insert_after): handle sibling == iter
+       (gtk_tree_store_prepend): remove stamp checks
+       (gtk_tree_store_insert_before): ditto
+       (gtk_tree_store_append): ditto
+       (gtk_tree_store_get_path): ditto
+       (gtk_tree_store_get_value): ditto
+       (gtk_tree_store_iter_has_child): ditto
+       (gtk_tree_store_iter_n_children): ditto
+       (gtk_tree_store_iter_nth_child): ditto
+       (gtk_tree_store_insert_after): ditto
+       (gtk_tree_store_is_ancestor): ditto
+       (gtk_tree_store_iter_depth): ditto
+       (gtk_tree_store_insert_before): assert that sibling's parent is
+       the same as the passed-in parent
+       (gtk_tree_store_insert_after): assert that sibling's parent is
+       the same as the passed-in parent
+
+       
+       * gtk/gtktreemodel.c (gtk_tree_model_get_first): new convenience 
+       function to get the first iterator in a model
+       
+       * gtk/gtktreestore.c (gtk_tree_store_get_root_iter): remove,
+       conventionally the "root" in this sense is just NULL afaict.
+
+       * gtk/gtkliststore.c (gtk_list_store_insert_before): handle case
+       where sibling == iter
+       (gtk_list_store_insert_after): handle case where sibling == iter
+
+       * tests/testtreeview.c (run_automated_tests): fairly lame basic
+       automated tests for ListStore, TreeStore
+
+        * gtk/gtkliststore.c (gtk_list_store_remove): update tail pointer
+       (gtk_list_store_insert): update tail pointer, and fix it to work
+       (gtk_list_store_insert_before): update tail pointer, and fix it to work
+       (gtk_list_store_append): use tail to be faster
+       (gtk_list_store_prepend): fix it, update tail pointer
+       (gtk_list_store_insert_after): fix it, update tail pointer
+
+       * gtk/gtkliststore.h (struct _GtkListStore): add tail pointer for 
+       the list
+
 2001-01-09  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtklabel.c (gtk_label_expose): don't draw if label->layout
index 39ee2fb8283c263641fb917dff0fefcfc0c14dda..8e480dd1dc91091f86be723c8731d910faf10e87 100644 (file)
@@ -1,3 +1,48 @@
+2001-01-10  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreestore.c (gtk_tree_store_insert_before): handle case
+       where sibling == iter
+       (gtk_tree_store_insert_after): handle sibling == iter
+       (gtk_tree_store_prepend): remove stamp checks
+       (gtk_tree_store_insert_before): ditto
+       (gtk_tree_store_append): ditto
+       (gtk_tree_store_get_path): ditto
+       (gtk_tree_store_get_value): ditto
+       (gtk_tree_store_iter_has_child): ditto
+       (gtk_tree_store_iter_n_children): ditto
+       (gtk_tree_store_iter_nth_child): ditto
+       (gtk_tree_store_insert_after): ditto
+       (gtk_tree_store_is_ancestor): ditto
+       (gtk_tree_store_iter_depth): ditto
+       (gtk_tree_store_insert_before): assert that sibling's parent is
+       the same as the passed-in parent
+       (gtk_tree_store_insert_after): assert that sibling's parent is
+       the same as the passed-in parent
+
+       
+       * gtk/gtktreemodel.c (gtk_tree_model_get_first): new convenience 
+       function to get the first iterator in a model
+       
+       * gtk/gtktreestore.c (gtk_tree_store_get_root_iter): remove,
+       conventionally the "root" in this sense is just NULL afaict.
+
+       * gtk/gtkliststore.c (gtk_list_store_insert_before): handle case
+       where sibling == iter
+       (gtk_list_store_insert_after): handle case where sibling == iter
+
+       * tests/testtreeview.c (run_automated_tests): fairly lame basic
+       automated tests for ListStore, TreeStore
+
+        * gtk/gtkliststore.c (gtk_list_store_remove): update tail pointer
+       (gtk_list_store_insert): update tail pointer, and fix it to work
+       (gtk_list_store_insert_before): update tail pointer, and fix it to work
+       (gtk_list_store_append): use tail to be faster
+       (gtk_list_store_prepend): fix it, update tail pointer
+       (gtk_list_store_insert_after): fix it, update tail pointer
+
+       * gtk/gtkliststore.h (struct _GtkListStore): add tail pointer for 
+       the list
+
 2001-01-09  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtklabel.c (gtk_label_expose): don't draw if label->layout
index 39ee2fb8283c263641fb917dff0fefcfc0c14dda..8e480dd1dc91091f86be723c8731d910faf10e87 100644 (file)
@@ -1,3 +1,48 @@
+2001-01-10  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreestore.c (gtk_tree_store_insert_before): handle case
+       where sibling == iter
+       (gtk_tree_store_insert_after): handle sibling == iter
+       (gtk_tree_store_prepend): remove stamp checks
+       (gtk_tree_store_insert_before): ditto
+       (gtk_tree_store_append): ditto
+       (gtk_tree_store_get_path): ditto
+       (gtk_tree_store_get_value): ditto
+       (gtk_tree_store_iter_has_child): ditto
+       (gtk_tree_store_iter_n_children): ditto
+       (gtk_tree_store_iter_nth_child): ditto
+       (gtk_tree_store_insert_after): ditto
+       (gtk_tree_store_is_ancestor): ditto
+       (gtk_tree_store_iter_depth): ditto
+       (gtk_tree_store_insert_before): assert that sibling's parent is
+       the same as the passed-in parent
+       (gtk_tree_store_insert_after): assert that sibling's parent is
+       the same as the passed-in parent
+
+       
+       * gtk/gtktreemodel.c (gtk_tree_model_get_first): new convenience 
+       function to get the first iterator in a model
+       
+       * gtk/gtktreestore.c (gtk_tree_store_get_root_iter): remove,
+       conventionally the "root" in this sense is just NULL afaict.
+
+       * gtk/gtkliststore.c (gtk_list_store_insert_before): handle case
+       where sibling == iter
+       (gtk_list_store_insert_after): handle case where sibling == iter
+
+       * tests/testtreeview.c (run_automated_tests): fairly lame basic
+       automated tests for ListStore, TreeStore
+
+        * gtk/gtkliststore.c (gtk_list_store_remove): update tail pointer
+       (gtk_list_store_insert): update tail pointer, and fix it to work
+       (gtk_list_store_insert_before): update tail pointer, and fix it to work
+       (gtk_list_store_append): use tail to be faster
+       (gtk_list_store_prepend): fix it, update tail pointer
+       (gtk_list_store_insert_after): fix it, update tail pointer
+
+       * gtk/gtkliststore.h (struct _GtkListStore): add tail pointer for 
+       the list
+
 2001-01-09  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtklabel.c (gtk_label_expose): don't draw if label->layout
index 39ee2fb8283c263641fb917dff0fefcfc0c14dda..8e480dd1dc91091f86be723c8731d910faf10e87 100644 (file)
@@ -1,3 +1,48 @@
+2001-01-10  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/gtktreestore.c (gtk_tree_store_insert_before): handle case
+       where sibling == iter
+       (gtk_tree_store_insert_after): handle sibling == iter
+       (gtk_tree_store_prepend): remove stamp checks
+       (gtk_tree_store_insert_before): ditto
+       (gtk_tree_store_append): ditto
+       (gtk_tree_store_get_path): ditto
+       (gtk_tree_store_get_value): ditto
+       (gtk_tree_store_iter_has_child): ditto
+       (gtk_tree_store_iter_n_children): ditto
+       (gtk_tree_store_iter_nth_child): ditto
+       (gtk_tree_store_insert_after): ditto
+       (gtk_tree_store_is_ancestor): ditto
+       (gtk_tree_store_iter_depth): ditto
+       (gtk_tree_store_insert_before): assert that sibling's parent is
+       the same as the passed-in parent
+       (gtk_tree_store_insert_after): assert that sibling's parent is
+       the same as the passed-in parent
+
+       
+       * gtk/gtktreemodel.c (gtk_tree_model_get_first): new convenience 
+       function to get the first iterator in a model
+       
+       * gtk/gtktreestore.c (gtk_tree_store_get_root_iter): remove,
+       conventionally the "root" in this sense is just NULL afaict.
+
+       * gtk/gtkliststore.c (gtk_list_store_insert_before): handle case
+       where sibling == iter
+       (gtk_list_store_insert_after): handle case where sibling == iter
+
+       * tests/testtreeview.c (run_automated_tests): fairly lame basic
+       automated tests for ListStore, TreeStore
+
+        * gtk/gtkliststore.c (gtk_list_store_remove): update tail pointer
+       (gtk_list_store_insert): update tail pointer, and fix it to work
+       (gtk_list_store_insert_before): update tail pointer, and fix it to work
+       (gtk_list_store_append): use tail to be faster
+       (gtk_list_store_prepend): fix it, update tail pointer
+       (gtk_list_store_insert_after): fix it, update tail pointer
+
+       * gtk/gtkliststore.h (struct _GtkListStore): add tail pointer for 
+       the list
+
 2001-01-09  Havoc Pennington  <hp@redhat.com>
 
        * gtk/gtklabel.c (gtk_label_expose): don't draw if label->layout
index 8c6b4cff169ada74b191fc43348b260aa8bc6757..b045f2e60d83f2a6ccf7f19b1c8c711ee029df64 100644 (file)
@@ -171,6 +171,7 @@ static void
 gtk_list_store_init (GtkListStore *list_store)
 {
   list_store->root = NULL;
+  list_store->tail = NULL;
   list_store->stamp = g_random_int ();
 }
 
@@ -612,6 +613,39 @@ gtk_list_store_get (GtkListStore *list_store,
   va_end (var_args);
 }
 
+static GSList*
+remove_link_saving_prev (GSList  *list,
+                         GSList  *link,
+                         GSList **prevp)
+{
+  GSList *tmp;
+  GSList *prev;
+
+  prev = NULL;
+  tmp = list;
+
+  while (tmp)
+    {
+      if (tmp == link)
+       {
+         if (prev)
+           prev->next = tmp->next;
+         if (list == tmp)
+           list = list->next;
+
+         tmp->next = NULL;
+         break;
+       }
+
+      prev = tmp;
+      tmp = tmp->next;
+    }
+
+  *prevp = prev;
+  
+  return list;
+}
+
 void
 gtk_list_store_remove (GtkListStore *list_store,
                       GtkTreeIter  *iter)
@@ -620,14 +654,25 @@ gtk_list_store_remove (GtkListStore *list_store,
 
   g_return_if_fail (list_store != NULL);
   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
-
+  g_return_if_fail (iter->user_data != NULL);
+  
   if (G_SLIST (iter->user_data)->data)
     _gtk_tree_data_list_free ((GtkTreeDataList *) G_SLIST (iter->user_data)->data,
                              list_store->column_headers);
 
   path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
-  list_store->root = g_slist_remove_link (G_SLIST (list_store->root),
-                                         G_SLIST (iter->user_data));
+
+  {
+    GSList *prev = NULL;
+    
+    list_store->root = remove_link_saving_prev (G_SLIST (list_store->root),
+                                                G_SLIST (iter->user_data),
+                                                &prev);
+    
+    if (iter->user_data == list_store->tail)
+      list_store->tail = prev;
+  }
+  
   list_store->stamp ++;
   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
                           "deleted",
@@ -635,6 +680,23 @@ gtk_list_store_remove (GtkListStore *list_store,
   gtk_tree_path_free (path);
 }
 
+static void
+insert_after (GtkListStore *list_store,
+              GSList       *sibling,
+              GSList       *new_list)
+{
+  g_return_if_fail (sibling != NULL);
+  g_return_if_fail (new_list != NULL);
+  
+  /* insert new node after list */
+  new_list->next = sibling->next;
+  sibling->next = new_list;
+
+  /* if list was the tail, the new node is the new tail */
+  if (sibling == list_store->tail)
+    list_store->tail = new_list;
+}
+
 void
 gtk_list_store_insert (GtkListStore *list_store,
                       GtkTreeIter  *iter,
@@ -642,11 +704,12 @@ gtk_list_store_insert (GtkListStore *list_store,
 {
   GSList *list;
   GtkTreePath *path;
-
+  GSList *new_list;
+  
   g_return_if_fail (list_store != NULL);
   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
   g_return_if_fail (iter != NULL);
-  g_return_if_fail (position < 0);
+  g_return_if_fail (position >= 0);
 
   if (position == 0)
     {
@@ -654,15 +717,21 @@ gtk_list_store_insert (GtkListStore *list_store,
       return;
     }
 
-  iter->stamp = list_store->stamp;
-  iter->user_data = g_slist_alloc ();
+  new_list = g_slist_alloc ();
 
   list = g_slist_nth (G_SLIST (list_store->root), position - 1);
-  if (list)
+
+  if (list == NULL)
     {
-      G_SLIST (iter->user_data)->next = list->next;
-      list->next = G_SLIST (iter->user_data)->next;
+      g_warning ("%s: position %d is off the end of the list\n", G_STRLOC, position);
+      return;
     }
+
+  insert_after (list_store, list, new_list);
+  
+  iter->stamp = list_store->stamp;
+  iter->user_data = new_list;
+  
   path = gtk_tree_path_new ();
   gtk_tree_path_append_index (path, position);
   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
@@ -677,22 +746,20 @@ gtk_list_store_insert_before (GtkListStore *list_store,
                              GtkTreeIter  *sibling)
 {
   GtkTreePath *path;
-  GSList *list, *prev;
+  GSList *list, *prev, *new_list;
   gint i = 0;
 
   g_return_if_fail (list_store != NULL);
   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
   g_return_if_fail (iter != NULL);
-  g_return_if_fail (G_SLIST (iter)->next == NULL);
 
   if (sibling == NULL)
     {
       gtk_list_store_append (list_store, iter);
       return;
     }
-
-  iter->stamp = list_store->stamp;
-  iter->user_data = g_slist_alloc ();
+  
+  new_list = g_slist_alloc ();
 
   prev = list = list_store->root;
   while (list && list != sibling->user_data)
@@ -701,17 +768,35 @@ gtk_list_store_insert_before (GtkListStore *list_store,
       list = list->next;
       i++;
     }
+
+  if (list != sibling->user_data)
+    {
+      g_warning ("%s: sibling iterator invalid? not found in the list", G_STRLOC);
+      return;
+    }
+
+  /* if there are no nodes, we become the list tail, otherwise we
+   * are inserting before any existing nodes so we can't change
+   * the tail
+   */
+
+  if (list_store->root == NULL)
+    list_store->tail = new_list;
   
   if (prev)
     {
-      prev->next = iter->user_data;
+      new_list->next = prev->next;
+      prev->next = new_list;
     }
   else
     {
-      G_SLIST (iter->user_data)->next = list_store->root;
-      list_store->root = iter->user_data;
+      new_list->next = list_store->root;
+      list_store->root = new_list;
     }
 
+  iter->stamp = list_store->stamp;
+  iter->user_data = new_list;
+  
   path = gtk_tree_path_new ();
   gtk_tree_path_append_index (path, i);
   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
@@ -726,12 +811,12 @@ gtk_list_store_insert_after (GtkListStore *list_store,
                             GtkTreeIter  *sibling)
 {
   GtkTreePath *path;
-  GSList *list;
+  GSList *list, *new_list;
   gint i = 0;
 
   g_return_if_fail (list_store != NULL);
   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
-  g_return_if_fail (iter == NULL);
+  g_return_if_fail (iter != NULL);
   if (sibling)
     g_return_if_fail (sibling->stamp == list_store->stamp);
 
@@ -744,14 +829,15 @@ gtk_list_store_insert_after (GtkListStore *list_store,
   for (list = list_store->root; list && list != sibling->user_data; list = list->next)
     i++;
 
-  g_return_if_fail (list != NULL);
+  g_return_if_fail (list == sibling->user_data);
 
-  iter->stamp = list_store->stamp;
-  iter->user_data = g_slist_alloc ();
-
-  G_SLIST (iter->user_data)->next = G_SLIST (sibling->user_data)->next;
-  G_SLIST (sibling)->next = G_SLIST (iter);
+  new_list = g_slist_alloc ();
 
+  insert_after (list_store, list, new_list);
+  
+  iter->stamp = list_store->stamp;
+  iter->user_data = new_list;
+  
   path = gtk_tree_path_new ();
   gtk_tree_path_append_index (path, i);
   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
@@ -773,6 +859,9 @@ gtk_list_store_prepend (GtkListStore *list_store,
   iter->stamp = list_store->stamp;
   iter->user_data = g_slist_alloc ();
 
+  if (list_store->root == NULL)
+    list_store->tail = iter->user_data;
+  
   G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
   list_store->root = iter->user_data;
 
@@ -789,7 +878,6 @@ gtk_list_store_append (GtkListStore *list_store,
                       GtkTreeIter  *iter)
 {
   GtkTreePath *path;
-  GSList *list, *prev;
   gint i = 0;
 
   g_return_if_fail (list_store != NULL);
@@ -799,19 +887,13 @@ gtk_list_store_append (GtkListStore *list_store,
   iter->stamp = list_store->stamp;
   iter->user_data = g_slist_alloc ();
 
-  prev = list = list_store->root;
-  while (list)
-    {
-      prev = list;
-      list = list->next;
-      i++;
-    }
-  
-  if (prev)
-    prev->next = iter->user_data;
+  if (list_store->tail)
+    list_store->tail->next = iter->user_data;
   else
     list_store->root = iter->user_data;
 
+  list_store->tail = iter->user_data;
+  
   path = gtk_tree_path_new ();
   gtk_tree_path_append_index (path, i);
   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
index ff01ea37fc59bb1c56c64563a28525753ab54e43..55ad276a01bbb8a9c7d0584c382e2f83e74700ba 100644 (file)
@@ -42,6 +42,7 @@ struct _GtkListStore
   /*< private >*/
   gint stamp;
   gpointer root;
+  GSList *tail;
   gint n_columns;
   GType *column_headers;
 };
index b3bbaca07daab4ef6595dd6bee4deb1f4c9d1d81..c1afaa3e51b3bc60d433eb308840cfa63c6b892f 100644 (file)
@@ -542,6 +542,36 @@ gtk_tree_model_get_iter (GtkTreeModel *tree_model,
   return TRUE;
 }
 
+/**
+ * gtk_tree_model_get_first:
+ * @tree_model: a #GtkTreeModel
+ * @iter: iterator to initialize
+ * 
+ * Initialized @iter with the first iterator in the tree (the one at the
+ * root path) and returns %TRUE, or returns %FALSE if there are no
+ * iterable locations in the model (i.e. the tree is empty).
+ * 
+ * Return value: %TRUE if @iter was initialized
+ **/
+gboolean
+gtk_tree_model_get_first (GtkTreeModel *tree_model,
+                          GtkTreeIter  *iter)
+{
+  gboolean retval;
+  GtkTreePath *path;
+  
+  g_return_val_if_fail (GTK_IS_TREE_MODEL (tree_model), FALSE);
+  g_return_val_if_fail (iter != NULL, FALSE);
+
+  path = gtk_tree_path_new_root ();
+
+  retval = gtk_tree_model_get_iter (tree_model, iter, path);
+
+  gtk_tree_path_free (path);
+
+  return retval;
+}
+
 /**
  * gtk_tree_model_get_path:
  * @tree_model: A #GtkTreeModel.
index c91a7b60f553a998e7d30896891d2061636b1cbf..74fd34da7e863853279dca0c2db0533f746d01ae 100644 (file)
@@ -152,6 +152,8 @@ GType        gtk_tree_model_get_column_type (GtkTreeModel      *tree_model,
 gboolean     gtk_tree_model_get_iter        (GtkTreeModel      *tree_model,
                                             GtkTreeIter       *iter,
                                             GtkTreePath       *path);
+gboolean     gtk_tree_model_get_first       (GtkTreeModel      *tree_model,
+                                             GtkTreeIter       *iter);
 GtkTreePath *gtk_tree_model_get_path        (GtkTreeModel      *tree_model,
                                             GtkTreeIter       *iter);
 void         gtk_tree_model_get_value       (GtkTreeModel      *tree_model,
index 0c4bc516dfe83ae8c50cb507dd3e940c8dbdca8d..aa8c658368f94105507269517bf95d1a6522edff 100644 (file)
@@ -285,10 +285,12 @@ gtk_tree_store_get_path (GtkTreeModel *tree_model,
   g_return_val_if_fail (tree_model != NULL, NULL);
   g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), NULL);
   g_return_val_if_fail (iter != NULL, NULL);
-  g_return_val_if_fail (GTK_TREE_STORE (tree_model)->stamp == iter->stamp, NULL);
+
   if (iter->user_data == NULL)
     return NULL;
 
+  g_assert (G_NODE (iter->user_data)->parent != NULL);
+  
   if (G_NODE (iter->user_data)->parent == G_NODE (GTK_TREE_STORE (tree_model)->root))
     {
       retval = gtk_tree_path_new ();
@@ -346,7 +348,6 @@ gtk_tree_store_get_value (GtkTreeModel *tree_model,
   g_return_if_fail (tree_model != NULL);
   g_return_if_fail (GTK_IS_TREE_STORE (tree_model));
   g_return_if_fail (iter != NULL);
-  g_return_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->stamp);
   g_return_if_fail (column < GTK_TREE_STORE (tree_model)->n_columns);
 
   list = G_NODE (iter->user_data)->data;
@@ -400,7 +401,6 @@ gtk_tree_store_iter_has_child (GtkTreeModel *tree_model,
   g_return_val_if_fail (tree_model != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), FALSE);
   g_return_val_if_fail (iter != NULL, FALSE);
-  g_return_val_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->stamp, FALSE);
 
   return G_NODE (iter->user_data)->children != NULL;
 }
@@ -414,8 +414,6 @@ gtk_tree_store_iter_n_children (GtkTreeModel *tree_model,
 
   g_return_val_if_fail (tree_model != NULL, 0);
   g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 0);
-  if (iter)
-    g_return_val_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->stamp, 0);
 
   if (iter == NULL)
     node = G_NODE (GTK_TREE_STORE (tree_model)->root)->children;
@@ -441,8 +439,6 @@ gtk_tree_store_iter_nth_child (GtkTreeModel *tree_model,
   g_return_val_if_fail (tree_model != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), FALSE);
   g_return_val_if_fail (iter != NULL, FALSE);
-  if (parent)
-    g_return_val_if_fail (parent->stamp == GTK_TREE_STORE (tree_model)->stamp, FALSE);
 
   if (parent == NULL)
     parent_node = GTK_TREE_STORE (tree_model)->root;
@@ -464,12 +460,15 @@ gtk_tree_store_iter_parent (GtkTreeModel *tree_model,
                            GtkTreeIter  *iter,
                            GtkTreeIter  *child)
 {
+  g_assert (G_NODE (child->user_data)->parent != NULL);
+  
   iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
   iter->user_data = G_NODE (child->user_data)->parent;
 
   if (iter->user_data == GTK_TREE_STORE (tree_model)->root)
     {
       iter->stamp = 0;
+      iter->user_data = NULL;
       return FALSE;
     }
 
@@ -677,6 +676,8 @@ gtk_tree_store_remove (GtkTreeStore *model,
 
   parent = G_NODE (iter->user_data)->parent;
 
+  g_assert (parent != NULL);
+  
   if (G_NODE (iter->user_data)->data)
     _gtk_tree_data_list_free ((GtkTreeDataList *) G_NODE (iter->user_data)->data,
                              model->column_headers);
@@ -691,6 +692,7 @@ gtk_tree_store_remove (GtkTreeStore *model,
   if (parent != G_NODE (model->root) && parent->children == NULL)
     {
       gtk_tree_path_up (path);
+      
       gtk_signal_emit_by_name (GTK_OBJECT (model),
                               "child_toggled",
                               path,
@@ -706,7 +708,7 @@ gtk_tree_store_insert (GtkTreeStore *model,
                       gint          position)
 {
   GtkTreePath *path;
-
+  
   g_return_if_fail (model != NULL);
   g_return_if_fail (GTK_IS_TREE_STORE (model));
 
@@ -731,30 +733,35 @@ gtk_tree_store_insert_before (GtkTreeStore *model,
                              GtkTreeIter  *sibling)
 {
   GtkTreePath *path;
-  GNode *parent_node = NULL;
-
+  GNode *parent_node = NULL;  
+  GNode *new_node;
+  
   g_return_if_fail (model != NULL);
   g_return_if_fail (GTK_IS_TREE_STORE (model));
   g_return_if_fail (iter != NULL);
-  if (parent != NULL)
-    g_return_if_fail (parent->stamp == model->stamp);
-  if (sibling != NULL)
-    g_return_if_fail (sibling->stamp == model->stamp);
 
-  iter->stamp = model->stamp;
-  iter->user_data = g_node_new (NULL);
+  new_node = g_node_new (NULL);  
 
   if (parent == NULL && sibling == NULL)
     parent_node = model->root;
   else if (parent == NULL)
     parent_node = G_NODE (sibling->user_data)->parent;
-  else
+  else if (sibling == NULL)
     parent_node = G_NODE (parent->user_data);
+  else
+    {
+      g_return_if_fail (G_NODE (sibling->user_data)->parent ==
+                        G_NODE (parent->user_data));
+      parent_node = G_NODE (parent->user_data);
+    }
 
   g_node_insert_before (parent_node,
                        sibling ? G_NODE (sibling->user_data) : NULL,
-                       G_NODE (iter->user_data));
+                        new_node);
 
+  iter->stamp = model->stamp;
+  iter->user_data = new_node;
+  
   path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
   gtk_signal_emit_by_name (GTK_OBJECT (model),
                           "inserted",
@@ -770,29 +777,35 @@ gtk_tree_store_insert_after (GtkTreeStore *model,
 {
   GtkTreePath *path;
   GNode *parent_node;
-
+  GNode *new_node;
+  
   g_return_if_fail (model != NULL);
   g_return_if_fail (GTK_IS_TREE_STORE (model));
   g_return_if_fail (iter != NULL);
-  if (parent != NULL)
-    g_return_if_fail (parent->stamp == model->stamp);
-  if (sibling != NULL)
-    g_return_if_fail (sibling->stamp == model->stamp);
 
-  iter->stamp = model->stamp;
-  iter->user_data = g_node_new (NULL);
+  new_node = g_node_new (NULL);
 
   if (parent == NULL && sibling == NULL)
     parent_node = model->root;
   else if (parent == NULL)
     parent_node = G_NODE (sibling->user_data)->parent;
-  else
+  else if (sibling == NULL)
     parent_node = G_NODE (parent->user_data);
+  else
+    {
+      g_return_if_fail (G_NODE (sibling->user_data)->parent ==
+                        G_NODE (parent->user_data));
+      parent_node = G_NODE (parent->user_data);
+    }
 
+  
   g_node_insert_after (parent_node,
                       sibling ? G_NODE (sibling->user_data) : NULL,
-                      G_NODE (iter->user_data));
-
+                       new_node);
+  
+  iter->stamp = model->stamp;
+  iter->user_data = new_node;
+  
   path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
   gtk_signal_emit_by_name (GTK_OBJECT (model),
                           "inserted",
@@ -806,27 +819,25 @@ gtk_tree_store_prepend (GtkTreeStore *model,
                        GtkTreeIter  *parent)
 {
   GNode *parent_node;
-
+  
   g_return_if_fail (model != NULL);
   g_return_if_fail (GTK_IS_TREE_STORE (model));
   g_return_if_fail (iter != NULL);
-  if (parent != NULL)
-    g_return_if_fail (parent->stamp == model->stamp);
 
   if (parent == NULL)
     parent_node = model->root;
   else
     parent_node = parent->user_data;
-
-  iter->stamp = model->stamp;
-  iter->user_data = g_node_new (NULL);
-
+  
   if (parent_node->children == NULL)
     {
       GtkTreePath *path;
-
-      g_node_prepend (parent_node, G_NODE (iter->user_data));
-
+      
+      iter->stamp = model->stamp;
+      iter->user_data = g_node_new (NULL);
+      
+      g_node_prepend (parent_node, iter->user_data);
+      
       if (parent_node != model->root)
        {
          path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), parent);
@@ -862,8 +873,6 @@ gtk_tree_store_append (GtkTreeStore *model,
   g_return_if_fail (model != NULL);
   g_return_if_fail (GTK_IS_TREE_STORE (model));
   g_return_if_fail (iter != NULL);
-  if (parent != NULL)
-    g_return_if_fail (parent->stamp == model->stamp);
 
   if (parent == NULL)
     parent_node = model->root;
@@ -904,19 +913,6 @@ gtk_tree_store_append (GtkTreeStore *model,
     }
 }
 
-void
-gtk_tree_store_get_root_iter (GtkTreeStore *model,
-                             GtkTreeIter  *iter)
-{
-  g_return_if_fail (model != NULL);
-  g_return_if_fail (GTK_IS_TREE_STORE (model));
-  g_return_if_fail (iter != NULL);
-
-  iter->stamp = model->stamp;
-  iter->user_data = G_NODE (model->root)->children;
-}
-
-
 gboolean
 gtk_tree_store_is_ancestor (GtkTreeStore *model,
                            GtkTreeIter  *iter,
@@ -926,8 +922,6 @@ gtk_tree_store_is_ancestor (GtkTreeStore *model,
   g_return_val_if_fail (GTK_IS_TREE_STORE (model), FALSE);
   g_return_val_if_fail (iter != NULL, FALSE);
   g_return_val_if_fail (descendant != NULL, FALSE);
-  g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
-  g_return_val_if_fail (descendant->stamp == model->stamp, FALSE);
 
   return g_node_is_ancestor (G_NODE (iter->user_data),
                             G_NODE (descendant->user_data));
@@ -941,7 +935,6 @@ gtk_tree_store_iter_depth (GtkTreeStore *model,
   g_return_val_if_fail (model != NULL, 0);
   g_return_val_if_fail (GTK_IS_TREE_STORE (model), 0);
   g_return_val_if_fail (iter != NULL, 0);
-  g_return_val_if_fail (iter->stamp == model->stamp, 0);
 
   return g_node_depth (G_NODE (iter->user_data)) - 1;
 }
index ab6abefa1d24ce2a971861ba5684386e100cba65..b56c3f8ce4bcc9b56cb252b0a93cd96a63657128 100644 (file)
@@ -113,8 +113,6 @@ void          gtk_tree_store_prepend         (GtkTreeStore *tree_store,
 void          gtk_tree_store_append          (GtkTreeStore *tree_store,
                                              GtkTreeIter  *iter,
                                              GtkTreeIter  *parent);
-void          gtk_tree_store_get_root_iter   (GtkTreeStore *tree_store,
-                                             GtkTreeIter  *iter);
 gboolean      gtk_tree_store_is_ancestor     (GtkTreeStore *tree_store,
                                              GtkTreeIter  *iter,
                                              GtkTreeIter  *descendant);
index 3ddaf6e8973e2df70c6f4dfca94bf966d04cfbd0..dae6baab8434de6dcb60165a7c47834d835194ca 100644 (file)
@@ -1371,11 +1371,185 @@ create_prop_editor (GObject *object)
  * Automated testing
  */
 
+static void
+treestore_torture_recurse (GtkTreeStore *store,
+                           GtkTreeIter  *root,
+                           gint          depth)
+{
+  GtkTreeModel *model;
+  gint i;
+  GtkTreeIter iter;  
+  
+  model = GTK_TREE_MODEL (store);    
+
+  if (depth > 2)
+    return;
+
+  ++depth;
+
+  gtk_tree_store_append (store, &iter, root);
+  
+  gtk_tree_model_iter_children (model, &iter, root);
+  
+  i = 0;
+  while (i < 100)
+    {
+      gtk_tree_store_append (store, &iter, root);
+      ++i;
+    }
+
+  while (gtk_tree_model_iter_children (model, &iter, root))
+    gtk_tree_store_remove (store, &iter);
+
+  gtk_tree_store_append (store, &iter, root);
+
+  /* inserts before last node in tree */
+  i = 0;
+  while (i < 100)
+    {
+      gtk_tree_store_insert_before (store, &iter, root, &iter);
+      ++i;
+    }
+
+  /* inserts after the node before the last node */
+  i = 0;
+  while (i < 100)
+    {
+      gtk_tree_store_insert_after (store, &iter, root, &iter);
+      ++i;
+    }
+
+  /* inserts after the last node */
+  gtk_tree_store_append (store, &iter, root);
+    
+  i = 0;
+  while (i < 100)
+    {
+      gtk_tree_store_insert_after (store, &iter, root, &iter);
+      ++i;
+    }
+
+  /* remove everything again */
+  while (gtk_tree_model_iter_children (model, &iter, root))
+    gtk_tree_store_remove (store, &iter);
+
+
+    /* Prepends */
+  gtk_tree_store_prepend (store, &iter, root);
+    
+  i = 0;
+  while (i < 100)
+    {
+      gtk_tree_store_prepend (store, &iter, root);
+      ++i;
+    }
+
+  /* remove everything again */
+  while (gtk_tree_model_iter_children (model, &iter, root))
+    gtk_tree_store_remove (store, &iter);
+
+  gtk_tree_store_append (store, &iter, root);
+  gtk_tree_store_append (store, &iter, root);
+  gtk_tree_store_append (store, &iter, root);
+  gtk_tree_store_append (store, &iter, root);
+
+  while (gtk_tree_model_iter_children (model, &iter, root))
+    {
+      treestore_torture_recurse (store, &iter, depth);
+      gtk_tree_store_remove (store, &iter);
+    }
+}
+
 static void
 run_automated_tests (void)
 {
+  g_print ("Running automated tests...\n");
+  
   /* FIXME TreePath basic verification */
 
-  /* FIXME consistency checks on the models */
-  
+  /* FIXME generic consistency checks on the models */
+
+  {
+    /* Make sure list store mutations don't crash anything */
+    GtkListStore *store;
+    GtkTreeModel *model;
+    gint i;
+    GtkTreeIter iter;
+    
+    store = gtk_list_store_new_with_types (1, G_TYPE_INT);
+
+    model = GTK_TREE_MODEL (store);
+    
+    i = 0;
+    while (i < 100)
+      {
+        gtk_list_store_append (store, &iter);
+        ++i;
+      }
+
+    while (gtk_tree_model_get_first (model, &iter))
+      gtk_list_store_remove (store, &iter);
+
+    gtk_list_store_append (store, &iter);
+
+    /* inserts before last node in list */
+    i = 0;
+    while (i < 100)
+      {
+        gtk_list_store_insert_before (store, &iter, &iter);
+        ++i;
+      }
+
+    /* inserts after the node before the last node */
+    i = 0;
+    while (i < 100)
+      {
+        gtk_list_store_insert_after (store, &iter, &iter);
+        ++i;
+      }
+
+    /* inserts after the last node */
+    gtk_list_store_append (store, &iter);
+    
+    i = 0;
+    while (i < 100)
+      {
+        gtk_list_store_insert_after (store, &iter, &iter);
+        ++i;
+      }
+
+    /* remove everything again */
+    while (gtk_tree_model_get_first (model, &iter))
+      gtk_list_store_remove (store, &iter);
+
+
+    /* Prepends */
+    gtk_list_store_prepend (store, &iter);
+    
+    i = 0;
+    while (i < 100)
+      {
+        gtk_list_store_prepend (store, &iter);
+        ++i;
+      }
+
+    /* remove everything again */
+    while (gtk_tree_model_get_first (model, &iter))
+      gtk_list_store_remove (store, &iter);
+    
+    g_object_unref (G_OBJECT (store));
+  }
+
+  {
+    /* Make sure tree store mutations don't crash anything */
+    GtkTreeStore *store;
+    
+    store = gtk_tree_store_new_with_types (1, G_TYPE_INT);
+    
+    treestore_torture_recurse (store, NULL, 0);
+    
+    g_object_unref (G_OBJECT (store));
+  }
+
+  g_print ("Passed.\n");
 }